/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 8 -*- */
/*
 * gtractionbuttons.c
 * Copyright (C) Jonas Hagmar 2009 <gnotterdev@gmail.com>
 * 
 * gtractionbuttons.c is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * gtractionbuttons.c is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <gtk/gtk.h>
#include <gtk/gtkhbox.h>
#include <gtk/gtkbutton.h>
#include <gdk/gdkpixbuf.h>
#include <gtk/gtkimage.h>
#include <gtk/gtkcontainer.h>
#include "gtractionbuttons.h"

static char const *ICON_REPLY = PIXMAPDIR "reply.png";
static char const *ICON_RETWEET = PIXMAPDIR "retweet.png";

G_DEFINE_TYPE (GtrActionButtons, gtr_action_buttons, GTK_TYPE_EVENT_BOX);

enum {
  REPLY,
  RETWEET,
  LAST_SIGNAL
};

static guint ab_signals[LAST_SIGNAL] = { 0 };

typedef struct _GtrActionButtonsPrivate GtrActionButtonsPrivate;

struct _GtrActionButtonsPrivate {
  GtkWidget *vbox;
  gboolean revealed;
  guint cloak_timeout;
  gchar *id;
  gchar *text;
  gchar *user_screen_name;
  gpointer data;
  GtrActionButtonsMask mask;
};

#define GTR_ACTION_BUTTONS_GET_PRIVATE(o)  \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), GTR_TYPE_ACTION_BUTTONS, GtrActionButtonsPrivate))

static void reveal (GtrActionButtons *ab);

static void
cancel_cloak (GtrActionButtons *ab)
{
  GtrActionButtonsPrivate *priv = GTR_ACTION_BUTTONS_GET_PRIVATE (ab);

  if (priv->cloak_timeout)
  {
    g_source_remove (priv->cloak_timeout);
    priv->cloak_timeout = 0;
  }
}

static void
cloak (GtrActionButtons *ab)
{
  GtrActionButtonsPrivate *priv = GTR_ACTION_BUTTONS_GET_PRIVATE (ab);

  if (priv->revealed)
  {
    gtk_container_foreach (GTK_CONTAINER (priv->vbox),
                           (GtkCallback) gtk_widget_destroy, NULL);
    priv->revealed = FALSE;
  }
}

static int
handle_cloak_timeout (gpointer p)
{
  GtrActionButtons *ab = (GtrActionButtons*) p;
  GtrActionButtonsPrivate *priv = GTR_ACTION_BUTTONS_GET_PRIVATE (ab);
  priv->cloak_timeout = 0;
  cloak (ab);
  return 0;
}

static void
schedule_cloak (GtrActionButtons *ab)
{
  GtrActionButtonsPrivate *priv = GTR_ACTION_BUTTONS_GET_PRIVATE (ab);

  cancel_cloak (ab);

  priv->cloak_timeout = g_timeout_add (100, handle_cloak_timeout, ab);
}

static void
realize (GtkWidget *ab,
         gpointer   user_data)
{
  GdkWindow *window = gtk_widget_get_window (GTK_WIDGET (ab));
  GdkEventMask mask;
  mask = gdk_window_get_events (window);
  gdk_window_set_events (GDK_WINDOW (window), mask | GDK_LEAVE_NOTIFY_MASK | GDK_ENTER_NOTIFY_MASK);
}

static gboolean
enter_notify (GtkWidget *widget,
              GdkEventCrossing *event,
              gpointer          user_data)
{
  GtrActionButtons *ab = GTR_ACTION_BUTTONS (user_data);

  reveal (ab);

  return FALSE;
}

static gboolean
leave_notify (GtkWidget *widget,
              GdkEventCrossing *event,
              gpointer          user_data)
{
  GtrActionButtons *ab = GTR_ACTION_BUTTONS (user_data);

  schedule_cloak (ab);

  return FALSE;
}

static void 
reply_clicked (GtkButton *button, 
               GtrActionButtons *ab)
{
  g_signal_emit (GTK_WIDGET (ab), ab_signals[REPLY], 0);
}

static void 
retweet_clicked (GtkButton *button, 
                 GtrActionButtons *ab)
{
  g_signal_emit (GTK_WIDGET (ab), ab_signals[RETWEET], 0);
}

static void
reveal (GtrActionButtons *ab)
{
  GtkWidget *reply;
  GtkWidget *retweet;
  GdkPixbuf *pixbuf;
  GtkWidget *image;
  GtkWidget *hbox;

  GtrActionButtonsPrivate *priv = GTR_ACTION_BUTTONS_GET_PRIVATE (ab);

  if (!priv->revealed)
  {
    if (priv->mask & GTR_AB_REPLY)
    {

      hbox = gtk_hbox_new (FALSE, 0);

      gtk_box_pack_start (GTK_BOX (priv->vbox), GTK_WIDGET (hbox), FALSE, FALSE, 0);


      reply = gtk_button_new ();

      gtk_widget_set_tooltip_text (GTK_WIDGET (reply), "Reply");

      g_signal_connect (reply, "enter-notify-event", G_CALLBACK (enter_notify), ab);
      g_signal_connect (reply, "leave-notify-event", G_CALLBACK (leave_notify), ab);
      g_signal_connect (reply, "realize", G_CALLBACK (realize), NULL);

      g_signal_connect (reply, "clicked", G_CALLBACK (reply_clicked), ab);

      gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (reply), FALSE, FALSE, 0);

      pixbuf =  gdk_pixbuf_new_from_file_at_size (ICON_REPLY, 10, 10, NULL);

      image = gtk_image_new_from_pixbuf (pixbuf);

      gdk_pixbuf_unref (pixbuf);

      gtk_container_add (GTK_CONTAINER (reply), image);

    }

    if (priv->mask & GTR_AB_RETWEET)
    {


      hbox = gtk_hbox_new (FALSE, 0);

      gtk_box_pack_start (GTK_BOX (priv->vbox), GTK_WIDGET (hbox), FALSE, FALSE, 0);

      retweet = gtk_button_new ();

      gtk_widget_set_tooltip_text (GTK_WIDGET (retweet), "Retweet");

      g_signal_connect (retweet, "enter-notify-event", G_CALLBACK (enter_notify), ab);
      g_signal_connect (retweet, "leave-notify-event", G_CALLBACK (leave_notify), ab);
      g_signal_connect (retweet, "realize", G_CALLBACK (realize), NULL);

      g_signal_connect (retweet, "clicked", G_CALLBACK (retweet_clicked), ab);

      gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (retweet), FALSE, FALSE, 0);

      pixbuf =  gdk_pixbuf_new_from_file_at_size (ICON_RETWEET, 10, 10, NULL);

      image = gtk_image_new_from_pixbuf (pixbuf);

      gdk_pixbuf_unref (pixbuf);

      gtk_container_add (GTK_CONTAINER (retweet), image);

    }

    gtk_widget_show_all (GTK_WIDGET (priv->vbox));

    priv->revealed = TRUE;
  }
  else
  {
    cancel_cloak (ab);
  }
}

static void
gtr_action_buttons_init (GtrActionButtons *object)
{
  GtrActionButtonsPrivate *priv = GTR_ACTION_BUTTONS_GET_PRIVATE (object);
  GdkColor color;

  gdk_color_parse ("white", &color);
  gtk_widget_modify_bg (GTK_WIDGET (object), GTK_STATE_NORMAL, &color);

  priv->vbox = gtk_vbox_new (FALSE, 0);

  gtk_widget_set_size_request (GTK_WIDGET (priv->vbox), 24, 48);

  gtk_container_add (GTK_CONTAINER (object), GTK_WIDGET (priv->vbox));

  g_signal_connect (object, "enter-notify-event", G_CALLBACK (enter_notify), object);
  g_signal_connect (object, "leave-notify-event", G_CALLBACK (leave_notify), object);
  g_signal_connect (object, "realize", G_CALLBACK (realize), NULL);

  priv->revealed = FALSE;
  priv->cloak_timeout = 0;
  priv->id = NULL;
  priv->text = NULL;
  priv->user_screen_name = NULL;
  priv->data = NULL;
  priv->mask = 0;
}

static void
gtr_action_buttons_finalize (GObject *object)
{
  /* TODO: Add deinitalization code here */

  G_OBJECT_CLASS (gtr_action_buttons_parent_class)->finalize (object);
}

static void 
gtr_action_buttons_dispose (GObject *object)
{
  GtrActionButtonsPrivate *priv = GTR_ACTION_BUTTONS_GET_PRIVATE (object);

  if (priv->id != NULL)
  {
    g_free (priv->id);
    priv->id = NULL;
  }

  if (priv->text != NULL)
  {
    g_free (priv->text);
    priv->text = NULL;
  }


  if (priv->user_screen_name != NULL)
  {
    g_free (priv->user_screen_name);
    priv->user_screen_name = NULL;
  }

}

static void
gtr_action_buttons_class_init (GtrActionButtonsClass *klass)
{
  GObjectClass* object_class = G_OBJECT_CLASS (klass);
  /*GtkEventBoxClass* parent_class = GTK_EVENT_BOX_CLASS (klass);*/

  g_type_class_add_private (klass, sizeof (GtrActionButtonsPrivate));

  klass->reply = NULL;
  klass->retweet = NULL;

  ab_signals[REPLY] =
    g_signal_new ("reply",
                  G_OBJECT_CLASS_TYPE (object_class),
                  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (GtrActionButtonsClass, reply),
                  NULL, NULL,
                  g_cclosure_marshal_VOID__VOID,
                  G_TYPE_NONE, 0);

  ab_signals[RETWEET] =
    g_signal_new ("retweet",
                  G_OBJECT_CLASS_TYPE (object_class),
                  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (GtrActionButtonsClass, retweet),
                  NULL, NULL,
                  g_cclosure_marshal_VOID__VOID,
                  G_TYPE_NONE, 0);

  object_class->finalize = gtr_action_buttons_finalize;
  object_class->dispose = gtr_action_buttons_dispose;
}

GtkWidget*
gtr_action_buttons_new (void)
{
  return g_object_new (GTR_TYPE_ACTION_BUTTONS, NULL);
}

void gtr_action_buttons_set_id (GtrActionButtons *ab, gchar const *id)
{
  GtrActionButtonsPrivate *priv = GTR_ACTION_BUTTONS_GET_PRIVATE (ab);

  if (priv->id != NULL)
  {
    g_free (priv->id);
    priv->id = NULL;
  }

  if (id != NULL)
  {
    priv->id = g_strdup (id);
  }
}

gchar const *gtr_action_buttons_get_id (GtrActionButtons *ab)
{
  GtrActionButtonsPrivate *priv = GTR_ACTION_BUTTONS_GET_PRIVATE (ab);

  return priv->id;
}

void gtr_action_buttons_set_text (GtrActionButtons *ab, gchar const *text)
{
  GtrActionButtonsPrivate *priv = GTR_ACTION_BUTTONS_GET_PRIVATE (ab);

  if (priv->text != NULL)
  {
    g_free (priv->text);
    priv->text = NULL;
  }

  if (text != NULL)
  {
    priv->text = g_strdup (text);
  }
}

gchar const *gtr_action_buttons_get_text (GtrActionButtons *ab)
{
  GtrActionButtonsPrivate *priv = GTR_ACTION_BUTTONS_GET_PRIVATE (ab);

  return priv->text;
}

void gtr_action_buttons_set_user_screen_name (GtrActionButtons *ab, gchar const *user_screen_name)
{
  GtrActionButtonsPrivate *priv = GTR_ACTION_BUTTONS_GET_PRIVATE (ab);

  if (priv->user_screen_name != NULL)
  {
    g_free (priv->user_screen_name);
    priv->user_screen_name = NULL;
  }

  if (user_screen_name != NULL)
  {
    priv->user_screen_name = g_strdup (user_screen_name);
  }
}

gchar const *gtr_action_buttons_get_user_screen_name (GtrActionButtons *ab)
{
  GtrActionButtonsPrivate *priv = GTR_ACTION_BUTTONS_GET_PRIVATE (ab);

  return priv->user_screen_name;
}

void gtr_action_buttons_set_data (GtrActionButtons *ab, gpointer data)
{
  GtrActionButtonsPrivate *priv = GTR_ACTION_BUTTONS_GET_PRIVATE (ab);

  priv->data = data;
}

gpointer gtr_action_buttons_get_data (GtrActionButtons *ab)
{
  GtrActionButtonsPrivate *priv = GTR_ACTION_BUTTONS_GET_PRIVATE (ab);

  return priv->data;
}

void 
gtr_action_buttons_set_mask (GtrActionButtons *ab, GtrActionButtonsMask mask)
{
  GtrActionButtonsPrivate *priv = GTR_ACTION_BUTTONS_GET_PRIVATE (ab);

  priv->mask = mask;
}

void 
gtr_action_buttons_reveal (GtrActionButtons *ab)
{
  reveal (ab);
}

void 
gtr_action_buttons_schedule_cloak (GtrActionButtons *ab)
{
  schedule_cloak (ab);
}
